home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiscKit1.7.1
/
MiscKit
/
Source
/
MiscGISKit
/
MiscCoordConverter.m
< prev
next >
Wrap
Text File
|
1995-07-20
|
10KB
|
307 lines
/*========================= MiscCoordConverter.m ============================*/
/* MiscCoordConverter is an abstract super class that supports the writing of
converters between coordinate systems. All values are double precision
floating point numbers representing locations in a three dimensional
coordinate system.
DMA Release 0.8, Copyright @1993 by Genesis Project, Ltd. All Rights
Reserved. For further information on terms and conditions see
the MiscKit license.
HISTORY
10-Mar-93 Dale Amon at GPL
Created.
*/
#import <misckit/miscgiskit.h>
@implementation MiscCoordConverter
/*===========================================================================*/
/* Internal Class Subcontractor support methods */
/*===========================================================================*/
/* register a converter to the list of conversion subcontractors */
static id subcontractors = nil; /* Master list of converters */
+ registerSubcontractor: aConverter
{ if (!subcontractors)
subcontractors = [[List allocFromZone:[self zone]] init];
[subcontractors addObjectIfAbsent: aConverter];
return self;
}
/*---------------------------------------------------------------------------*/
/* unregister a converter from the list of conversion subcontractors */
+ unregisterSubcontractor: aConverter
{ [subcontractors removeObject:aConverter];
return self;
}
/*---------------------------------------------------------------------------*/
/* get the name of the next one in the list */
+ getSubcontractor:(unsigned int) n {return [subcontractors objectAt:n];}
/*===========================================================================*/
/* General Class methods */
/*===========================================================================*/
/* Initialize the class */
+ initialize
{[MiscCoordConverter setVersion:MISC_COORD_CONVERTER_VERSION_ID]; return self;}
/*===========================================================================*/
/* Initialization methods */
/*===========================================================================*/
/* We cache everything that we will need repeatedly, ie the class id's
of all the MiscCoord classes we know how to service.
Every instance of a converter is registered so it can be subcontracted
to.
*/
- init
{ [MiscCoordConverter registerSubcontractor: self];
return self;
}
/*---------------------------------------------------------------------------*/
/* Free self and subcontractor list, but NOT the subcontractors.
There is a potential problem: what if someone holds
a pointer to us? Some going out of business notification
would be necessary in that case.
Most subclasses lock out free so this is not an immediate problem
*/
- free
{ [MiscCoordConverter unregisterSubcontractor:self];
[services free];
return [self free];
}
/*===========================================================================*/
/* Service support methods */
/*===========================================================================*/
/* For subclass use: add a service to our list of conversion services. */
- addService: (SEL) aSelector convertsFrom: (Class) one to: (Class) two
{ struct __MiscService theService;
if (!services)
services = [[Storage allocFromZone:[self zone]]
initCount: 0
elementSize: MISC_SERVICE_SIZE
description: MISC_SERVICE_DESCRIPTION];
theService.iClass = one;
theService.oClass = two;
theService.xlator = aSelector;
[services addElement: (void*) &theService];
return self;
}
/*---------------------------------------------------------------------------*/
/* Internal method to search for a service in our list of conversion services.
We return the selector that can carry out the desired conversion,
or else a null selector if we cannot. It is assumed that a null selector
will always be undefined.
*/
- (SEL) findServiceFrom: (Class) one to: (Class) two
{ struct __MiscService *theService;
unsigned int i, cnt = [services count];
for (i=0; i<cnt; i++)
{ theService = (struct __MiscService *) [services elementAt:i];
if ((theService->iClass == one) &&
(theService->oClass == two)) return theService->xlator;
}
return (SEL) 0;
}
/*===========================================================================*/
/* Basic conversion methods (Internal use only) */
/*===========================================================================*/
/* Collect info we need to carry out the requested job
NOTE: Any method that is sent to srcCoord or dstCoord must be in
the MiscCoordConverterClient protocol!
*/
- prepareForJob: inCoord : outCoord
{
srcConstants = [inCoord constants];
dstConstants = [outCoord constants];
sameConstants = [srcConstants isEqual: dstConstants];
dimensions = [[inCoord class] dimensions];
npoints = [inCoord curBlockSize];
src = [inCoord curPtr];
dst = [outCoord curPtr];
return self;
}
/*---------------------------------------------------------------------------*/
/* a quick means of copying if data formats are identical. This method
is known outside by name, but should never be actually used outside
of applyTransform.
It will fail if the constants associated with the two MiscCoords are not
functionally the same.
*/
- (BOOL) copyCoords
{ int len;
if (!sameConstants) return NO;
len = dimensions * npoints * sizeof(double);
bcopy((char*)src, (char*)dst, len);
return YES;
}
/*---------------------------------------------------------------------------*/
/* Apply the specified method to a block of coordinates. Job is set up
by prepareForJob: before this method is called.
*/
- (BOOL) applyTransform:(SEL)aSelector
{ unsigned int i;
/* copy has it's own loop */
if (aSelector == @selector(copyCoords))
[self perform: aSelector];
else
for (i=0;
i<npoints;
i++,dst+=dimensions,src+=dimensions)
[self perform: aSelector];
return YES;
}
/*---------------------------------------------------------------------------*/
/* Conversion setup method. This method sees if we or anyone we know of
can handle the requested job. If so, we return YES with local instance
vars theTransform and subContractor ready to go.
NOTE: If you want to handle conversion between coords of different
dimensionality, look here first.
Both MiscCoords must:
1) Conform to the MiscCoordConverterClient protocol.
2) Have the same dimensionality.
3) Have the same transfer blocksize pre-set to the same size.
4) Some Converter object must be willing to accept the job
of converting or copying between the two types.
*/
- (BOOL) reviewSpecification: inCoord to: outCoord
{ unsigned int i;
Class srcClass, dstClass;
BOOL srcOk,dstOk;
srcClass = [inCoord class];
dstClass = [outCoord class];
srcOk = [srcClass conformsTo:@protocol(MiscCoordConverterClient)];
dstOk = [dstClass conformsTo:@protocol(MiscCoordConverterClient)];
if (!(srcOk && dstOk)) return NO;
if ([srcClass dimensions] != [dstClass dimensions]) return NO;
if ([inCoord curBlockSize] != [outCoord curBlockSize]) return NO;
/* We should be able to handle it ourselves most of the time, or
else the customer has the wrong delegate! */
if (theTransform = [self findServiceFrom: srcClass to: dstClass])
aSubcontractor = self;
else
/* If we can't do it ourselves, try subcontracting to one of the
other registered convertors
*/
for (i=0; aSubcontractor = [MiscCoordConverter getSubcontractor:i]; i++)
{if (aSubcontractor == self) continue;
if (theTransform =
[aSubcontractor findServiceFrom: srcClass to: dstClass])
break;
}
return ((theTransform) ? YES : NO);
}
/*===========================================================================*/
/* Misc Coord Converter Server protocol */
/*===========================================================================*/
/* Convert the specified block of coordinates from the source type to the
destination type if we are able, or if we can subcontract it to someone
else who is able to do it. If there is any reason at all that we
cannot, then return NO.
DESIGN NOTE: Although local methods are executing, there may be one OR two
different objects with private storage involved. Care must be taken to
make sure that setup takes place in the correct object, ie usually the
subcontractor object. The subcontractor will often be self, in which case
setting ivars in this method would work: but if not, the subcontractor
would probably crash because things would not be set up in ITS' ivars.
THINK before making changes to where set up occurs!
*/
- (BOOL) convert: inCoord to: outCoord
{
if (![self reviewSpecification: inCoord to: outCoord]) return NO;
[aSubcontractor prepareForJob: inCoord : outCoord];
return [aSubcontractor applyTransform:theTransform];
}
/*===========================================================================*/
/* For Subclass use: We have a fast means of copying, but there is no need to
make it really public. To discourage possibly disastrous attempts to use it
directly, we supply a means of getting it's selector for use in an
addService method by a subclass.
*/
- (SEL) fastCopySelector {return (@selector(copyCoords));}
/*===========================================================================*/
/* Archive methods */
/*===========================================================================*/
/* This class should not be used on its own. Presumably a subclass will
re-generate it's services list when it awakes, or if it is a single
instance class, it will just delete this object when it answers with
a finishUnarchiving message.
*/
- awake
{ [super awake];
services = nil;
[MiscCoordConverter registerSubcontractor: self];
return self;
}
@end